#pragma once

#include <vector>

struct XZ{
	XZ(float p_x = 0.0f, float p_z = 0.0f);
	float x;
	float z;
};

class CollisionManager;
class QuadTree;
struct XZBoundingBox{
	XZBoundingBox(void){}
	XZBoundingBox(const XZ& p_center, const XZ& p_half_dimension, void* p_user_data);
	void Relocate();
	XZ center;
	XZ half_dimension;
	QuadTree* owner;
	void* user_data;
};

struct AABB{
	AABB(void){}
	AABB(const XZ& p_center, const XZ& p_half_dimension);
	XZ center;
	XZ half_dimension;
	void Set(const XZ& p_center, const XZ& p_half_dimension);
	bool Intersects(XZBoundingBox* p_bounding_box);
	bool Intersects(const AABB& p_aabb);
};

class QuadTree{
public:
	QuadTree(bool is_root, QuadTree* root = nullptr);
	~QuadTree(void);

	void SetCollisionManager(CollisionManager* collision_manager) { m_collision_manager = collision_manager; }
	void Update();
	void CheckCollision();
	void Set(const AABB& p_boundary);
	void Subdivide(int subdivides);
	bool Insert(XZBoundingBox* bounding_box);
	void QueryRange(std::vector<XZBoundingBox*>& list, AABB& range);
	void GetBoundingBoxes(std::vector<XZBoundingBox*>& boxes);
	void RemoveBoundingBox(XZBoundingBox* bounding_box);
	bool Intersects(XZBoundingBox* bounding_box);
	CollisionManager* GetCollisionManager() const { return m_collision_manager; }
	QuadTree* GetParent() const { return m_parent; }
	QuadTree* GetRoot() const	{ return m_root; }

private:
	QuadTree*					m_north_west;
	QuadTree*					m_north_east;
	QuadTree*					m_south_west;
	QuadTree*					m_south_east;
	QuadTree*					m_parent;
	QuadTree*					m_root;

	AABB						m_boundary;
	const unsigned int			QT_NODE_CAPACITY;
	
	std::vector<XZBoundingBox*> m_bounding_boxes;
	CollisionManager* m_collision_manager;
};